package com.sdk;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.widget.Toast;

import com.com.unionpay.constant.Constant;

import org.eclipse.paho.android.service.MqttAndroidClient;
import org.eclipse.paho.client.mqttv3.IMqttActionListener;
import org.eclipse.paho.client.mqttv3.IMqttDeliveryToken;
import org.eclipse.paho.client.mqttv3.IMqttToken;
import org.eclipse.paho.client.mqttv3.MqttCallbackExtended;
import org.eclipse.paho.client.mqttv3.MqttConnectOptions;
import org.eclipse.paho.client.mqttv3.MqttException;
import org.eclipse.paho.client.mqttv3.MqttMessage;
import org.greenrobot.eventbus.EventBus;

import java.util.Locale;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

/**
 * mqtt 推送控制服务
 * Created by Lenovo on 2017/10/11.
 */

public class MQTTService {

    public static final String TAG = MQTTService.class.getSimpleName();


    private static final String MQTT_BROKER = "172.18.163.31"; // Broker Port

    private static final String MQTT_PORT = "1883"; // Broker Port
    private static final String MQTT_SSL_PORT = "8883"; // Broker Port

    private static final String MQTT_URL_FORMAT = "tcp://%s:%s"; // URL Format normally don't change
    private static final String MQTT_SSL_URL_FORMAT = "ssl://%s:%s"; // URL Format normally don't change
    private final Context context;

    private boolean isSSLEnable = false;

    private String mClientId = null;
    private ScheduledExecutorService scheduler;
    //private MqttAndroidClient mqttClient;
    private String userName = "admin"; // 连接的用户名
    private String passWord = "admin"; //连接的密码
    private String topic = "request"; // 连接的用户名

    private ConnectivityManager mConnectivityManager; // To check for connectivity changes
    private MqttConnectOptions options;

    private static MqttAndroidClient mqttClient;

    // qpboc交易
    public static final String TOPIC_QPOBC_REQUEST = "topic_qpboc_request";
    //    public static final String  TOPIC_QPOBC_RESPONSE = "topic_qpboc_response";
    public static final String TOPIC_QPOBC_RESPONSE = "iot/xiaomi";


    public void stopConnect() {
        try {
            context.unregisterReceiver(mConnectivityReceiver);
            mqttClient.unsubscribe(TOPIC_QPOBC_RESPONSE + "/" + mClientId);
            mqttClient.unregisterResources();
            mqttClient.disconnect();
            LogUtils.e("MQTT 断开连接");
        } catch (Exception e) {
            e.printStackTrace();
            LogUtils.e("MQTT 断开连接异常");
        }
    }

    public MQTTService(Context context) {
        super();
        this.context = context;
        mConnectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
        context.registerReceiver(mConnectivityReceiver, new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION));
    }

    /**
     * 初始化相关数据
     */
    public void init() {
        try {
            LogUtils.e("---------=+++++++++++-------");
            //clientId要唯一，不然会挤掉另外相同的clientId的连接
//            mClientId = "POS-" + SystemUtils.getIMEI(this);
            mClientId = "POS-1122";
            //host为主机名，test为clientid即连接MQTT的客户端ID，一般以客户端唯一标识符表示，MemoryPersistence设置clientid的保存形式，默认为以内存保存
            String url;
            if (isSSLEnable)
                url = String.format(Locale.US, MQTT_SSL_URL_FORMAT, MQTT_BROKER, MQTT_SSL_PORT);
            else {
                url = String.format(Locale.US, MQTT_URL_FORMAT, MQTT_BROKER, MQTT_PORT);
            }
            mqttClient = new MqttAndroidClient(context, url, mClientId);
            //MQTT的连接设置
            options = new MqttConnectOptions();
            //设置是否清空session,这里如果设置为false表示服务器会保留客户端的连接记录，这里设置为true表示每次连接到服务器都以新的身份连接
            options.setCleanSession(true);
            //设置连接的用户名
            options.setUserName(userName);
            //设置连接的密码
            options.setPassword(passWord.toCharArray());
            // 设置超时时间 单位为秒
            options.setConnectionTimeout(10);
            // 设置会话心跳时间 单位为秒 服务器会每隔1.5*value秒的时间向客户端发送个消息判断客户端是否在线，但这个方法并没有重连的机制
            options.setKeepAliveInterval(60);
            //设置自动重连
            options.setAutomaticReconnect(true);
//            mqttAsyncClient.connect(connOpts).waitForCompletion();

            if (isSSLEnable)
                options.setSocketFactory(SSLSocketClient.getSSLSocketFactory());
            //设置回调
            mqttClient.setCallback(mqttCallback);
        } catch (Exception e) {
            e.printStackTrace();
        }
        startReconnect();
    }

    // MQTT监听并且接受消息
    private MqttCallbackExtended mqttCallback = new MqttCallbackExtended() {

        @Override
        public void connectComplete(boolean reconnect, String s) {
            if (reconnect) {
                LogUtils.e("Re-connect");

            } else {
                LogUtils.e("first Connection ");
            }

            LogUtils.e("MQTT 连接成功");

            //添加订阅
            dosub();

        }

        private void dosub() {
            try {
                // 订阅mpboc话题
//                String topic = TOPIC_QPOBC_RESPONSE + "/" + mClientId;
                String topic = TOPIC_QPOBC_RESPONSE;
                mqttClient.subscribe(topic, 0);
                //LogUtils.writeToFile(LogUtils.LOGTYPE_MQTT_STATUS, "connected and subscribe success");

                LogUtils.e("MQTT 订阅" + TOPIC_QPOBC_RESPONSE + "成功");
                LogUtils.e("MQTT 订阅主题：" + topic);
            } catch (Exception e) {
                e.printStackTrace();
                LogUtils.e("MQTT 订阅异常 " + e.getMessage());
            }
        }

        @Override
        public void connectionLost(Throwable cause) {
            //连接丢失后，一般在这里面进行重连
            if (cause != null) {
                LogUtils.e("mqtt connectionLost,cause:" + cause.getMessage());
                //LogUtils.writeToFile(LogUtils.LOGTYPE_MQTT_STATUS, "mqtt connectionLost,cause:" + cause.getMessage());
            } else {
                LogUtils.e("mqtt connectionLost,cause:null");
                //LogUtils.writeToFile(LogUtils.LOGTYPE_MQTT_STATUS, "mqtt connectionLost,cause:null");
            }
            if (isNetworkAvailable()) {
                LogUtils.e("mqtt connectionLost,start Reconnect");

                startReconnect();
            }
        }

        @Override
        public void messageArrived(String topic, MqttMessage message) throws Exception {
            //收到消息推送时会回调
            String str1 = new String(message.getPayload());
            LogUtils.e("MQTT收到消息->" + "message:" + str1);
            EventBus.getDefault().post(new MessageEvent(Constant.EVENT_UPD_SUCCESS, ActiveMode.MQTT));

//            LogUtils.writeToFile(LogUtils.LOGTYPE_MQTT, str1);

//            if ("update".equals(str1)) {
//                //http://10.7.121.40:8161/admin/topics.jsp手动推送，APP更新
//                Beta.checkUpgrade();
//            } else {
//                //ME系统推送
//                PushJson pushJson = JSON.parseObject(str1, PushJson.class);
//                if ("0".equals(pushJson.getCode())) {
//                    EventBus.getDefault().post(pushJson);
//                } else {
//                    ErrorDialog.showAlert(mContext, pushJson.getMessage(), true);
//                }
//            }
        }

        @Override
        public void deliveryComplete(IMqttDeliveryToken token) {
            //publish后会执行到这里
            long messageId = token.getMessageId();
            LogUtils.e("messageId=:" + messageId);
        }

    };

    /**
     * Query's the NetworkInfo via ConnectivityManager
     * to return the current connected state
     * 通过ConnectivityManager查询网络连接状态
     *
     * @return boolean true if we are connected false otherwise
     * 如果网络状态正常则返回true反之flase
     */
    private boolean isNetworkAvailable() {
        NetworkInfo info = mConnectivityManager.getActiveNetworkInfo();
        return info != null && info.isConnected();
    }

    /**
     * Checkes the current connectivity
     * and reconnects if it is required.
     * 重新连接如果他是必须的
     */
    public synchronized void reconnectIfNecessary() {
        if (mqttClient == null || !mqttClient.isConnected()) {
            connect();
        }
    }

    private void connect() {
        new Thread(new Runnable() {

            @Override
            public void run() {
                try {
                    mqttClient.connect(options, null, iMqttActionListener);
                } catch (Exception e) {
                    e.printStackTrace();
                    // 连接出错，可以设置重新连接
                }
            }
        }).start();
    }

    // 消息发送成功
    private IMqttActionListener iMqttActionListener = new IMqttActionListener() {
        @Override
        public void onSuccess(IMqttToken token) {
            scheduler.shutdownNow();
//            try {
//                // 订阅mpboc话题
//                mqttClient.subscribe(TOPIC_QPOBC_RESPONSE, 0);
//                //LogUtils.writeToFile(LogUtils.LOGTYPE_MQTT_STATUS, "connected and subscribe success");
//                LogUtils.d("MQTT 订阅" + TOPIC_QPOBC_RESPONSE + "成功");
//            } catch (Exception e) {
//                e.printStackTrace();
//                LogUtils.e("MQTT 订阅异常 " + e.getMessage());
//            }
        }

        @Override
        public void onFailure(IMqttToken asyncActionToken, Throwable exception) {
            LogUtils.e("连接失败,exception:" + exception.getMessage());
            exception.printStackTrace();
        }
    };

    /**
     * 调用init() 方法之后，调用此方法。
     */
    public void startReconnect() {
        if (scheduler != null) {
            scheduler.shutdownNow();
        }
        scheduler = Executors.newSingleThreadScheduledExecutor();
        scheduler.scheduleAtFixedRate(new Runnable() {

            @Override
            public void run() {
                if (!mqttClient.isConnected() && isNetworkAvailable()) {
                    connect();
                }
            }
        }, 0, 10 * 1000, TimeUnit.MILLISECONDS);
    }

    private long mLastNetworkUnAvailableMills;

    /**
     * Receiver that listens for connectivity chanes
     * via ConnectivityManager
     * 网络状态发生变化接收器
     */
    public BroadcastReceiver mConnectivityReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            LogUtils.e("++++++++++++++++++++++++++++++++++");
            if (!isNetworkAvailable()) {
                LogUtils.e("无网络连接...");
                //处理网络断开时收到两次广播的情况
                long curMills = System.currentTimeMillis();
                if (curMills - mLastNetworkUnAvailableMills > 2000) {
                    mLastNetworkUnAvailableMills = curMills;
                    Toast.makeText(context, "网络不可用", Toast.LENGTH_SHORT).show();
                    if (scheduler != null) {
                        scheduler.shutdownNow();
                    }
                }
            } else {
                LogUtils.e("网络已连接...");
                if (mqttClient == null) {
                    init();
                } else {
                    // 重连失败,有自动重连机制
                    //startReconnect();
                }
            }
        }
    };

    public static void publish(String topic, String msg) {
        Integer qos = 0;
        Boolean retained = false;
        try {
            mqttClient.publish(topic, msg.getBytes(), qos.intValue(), retained.booleanValue());
            LogUtils.d("MQTT 发布" + topic + ", msg：" + msg);

        } catch (MqttException e) {
            e.printStackTrace();
        }
    }
}

